﻿using System;
using MugenInjection.Delegates;
using MugenInjection.Syntax.Type;

namespace MugenInjection.Syntax
{
    /// <summary>
    ///     Specific fluent syntax to create condition.
    /// </summary>
    public interface IConditionBuilder<T>
    {
        /// <summary>
        ///     Indicates that the condition should be registered with the specified name.
        /// </summary>
        /// <param name="name">The name to give the condition.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> Named(string name);

        /// <summary>
        /// Indicates that the condition should be registered with the specified key.
        /// </summary>
        /// <param name="key">The key to give the condition.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> Keyed(object key);

        /// <summary>
        ///     Indicates that the binding should be used only for requests that support the specified condition.
        /// </summary>
        /// <param name="canResolveBindingDelegate">
        ///     The specified <see cref="CanResolveBindingDelegate" />
        /// </param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> When(CanResolveBindingDelegate canResolveBindingDelegate);

        /// <summary>
        ///     Indicates that the binding should be used only for injections on the specified type.
        ///     Types that derive from the specified type will not be considered as valid target.
        /// </summary>
        /// <param name="type">The type of target.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenInto(System.Type type);

        /// <summary>
        ///     Indicates that the binding should be used only for injections on the specified type <see cref="TType" />.
        ///     Types that derive from the specified type will not be considered as valid target.
        /// </summary>
        /// <typeparam name="TType">The type of target.</typeparam>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenInto<TType>();

        /// <summary>
        ///     Indicates that the binding should be used only for injections on the specified type.
        ///     Types that derive from the specified type are considered as valid targets.
        /// </summary>
        /// <param name="type">The type of target.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenIntoIsAssignable(System.Type type);

        /// <summary>
        ///     Indicates that the binding should be used only for injections on the specified type <see cref="TType" />.
        ///     Types that derive from the specified type are considered as valid targets.
        /// </summary>
        /// <typeparam name="TType">The type of target.</typeparam>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenIntoIsAssignable<TType>();

        /// <summary>
        ///     Indicates that the binding should be used only for injections on the specified type when namespace equals.
        /// </summary>
        /// <param name="name">The name of namespace.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenNamespaceEqual(string name);

        /// <summary>
        ///     Indicates that the binding should be used only when the class being injected has
        ///     an attribute of the specified type.
        /// </summary>
        /// <param name="attributeType">The type of attribute.</param>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenClassHasAttribute(System.Type attributeType);

        /// <summary>
        ///     Indicates that the binding should be used only when the class being injected has
        ///     an attribute of the specified type.
        /// </summary>
        /// <typeparam name="TAttribute">The type of attribute.</typeparam>
        /// <returns>The fluent syntax.</returns>
        IConditionBuilder<T> WhenClassHasAttribute<TAttribute>() where TAttribute : Attribute;
    }
}